// ignore_for_file: avoid_print, constant_identifier_names, camel_case_types, non_constant_identifier_names, slash_for_doc_comments

import 'dart:ffi';
import 'dart:typed_data';
import 'dart:ffi' as ffi;

// ignore: depend_on_referenced_packages
import 'package:ffi/ffi.dart';

const INPUT_KEYBOARD = 1;
const KEYEVENTF_UNICODE = 0x0004;

DynamicLibrary _user32 = DynamicLibrary.open("user32.dll");
DynamicLibrary _kernel32 = DynamicLibrary.open("kernel32.dll");

typedef _SendInput_C =
    Uint32 Function(Uint32 cInputs, Pointer pInputs, Uint32 cbSize);
typedef _SendInput_Dart =
    int Function(int cInputs, Pointer pInputs, int cbSize);
var SendInput = _user32.lookupFunction<_SendInput_C, _SendInput_Dart>(
  "SendInput",
);

typedef _GetLastError_C = Uint32 Function();
typedef _GetLastError_Dart = int Function();
var GetLastError = _kernel32
    .lookupFunction<_GetLastError_C, _GetLastError_Dart>("GetLastError");

// void main() {
//   var zKeyVirtualCoe = 0x5a;
//   var event = KeyboardInput.allocate(vkey: zKeyVirtualCoe);
//   // this loop will send less than 10 'z' characters (sometimes even zero)
//   for (var i = 0; i < 10; i++) {
//     print('Sending $i-th virtual character');
//     var written = SendInput(1, event.addressOf, 40);
//     print('Written $written');
//     print('Error ${GetLastError()}');
//   }

//   // this does not work at all (despite the fact that it says 'written 1' - so it sent something)
//   var unicode =
//       KeyboardInput.allocate(scan: 'x'.codeUnitAt(0), flags: KEYEVENTF_UNICODE);
//   for (var i = 0; i < 10; i++) {
//     print('Sending $i-th unicode character');
//     var written = SendInput(
//         1, unicode.addressOf, 40); // note the size of 40 instead of 28
//     print('Written $written');
//     print('Error ${GetLastError()}');
//   }

//   print('Struct size: ${sizeOf<KeyboardInput>()}');
// }

// final class KeyboardInput extends Struct {
//   @Uint64()
//   external int type;
//   @Uint16()
//   external int virtualCode;
//   @Uint16()
//   external int scanCode;
//   @Uint64()
//   external int flags;
//   @Uint64()
//   external int time;
//   external Pointer dwExtraInfo;

//   factory KeyboardInput.allocate({int vkey = 0, int scan = 0, int flags = 0}) =>
//       malloc<KeyboardInput>().ref
//         ..type = INPUT_KEYBOARD
//         ..virtualCode = vkey
//         ..scanCode = scan
//         ..flags = flags
//         ..time = 0
//         ..dwExtraInfo = nullptr;
// }

// class KEYBDINPUT extends Struct {
//   @Uint32()
//   int type;
//   @Uint32()
//   int _padding;
//   @Uint16()
//   int wVk;
//   @Uint16()
//   int wScan;
//   @Uint32()
//   int dwFlags;
//   @Uint32()
//   int time;
//   Pointer dwExtraInfo;
//   @Uint64()
//   int _padding2;
// }

void by() {
  Uint8List bytes = Uint8List.fromList([0, 1, 2, 3]);
  ByteBuffer byteBuffer = bytes.buffer;
  Uint32List thirtytwoBitList = byteBuffer.asUint32List();
  print(thirtytwoBitList);
  print(Endian.host == Endian.little);

  ByteData byteData = ByteData.sublistView(bytes);
  int value = byteData.getUint16(0, Endian.big);
  print(value);

  byteData.setInt16(2, 256, Endian.big);

  String hex = 2024.toRadixString(16).padLeft(4, '0');
  print(hex);
  print(int.parse(hex, radix: 16));
  String bin = 2024.toRadixString(2);
  print(bin);

  List<int> cu = 'Hello🌞'.codeUnits;
  print(cu);

  // ignore: unused_local_variable
  final Pointer<Utf8> cs = calloc.allocate(14);
}

/**
hex  binary 
----------
0    0000
1    0001
2    0010
3    0011
4    0100
5    0101
6    0110
7    0111
8    1000
9    1001
A    1010
B    1011
C    1100
D    1101
E    1110
F    1111
 */

final DynamicLibrary stdlib = DynamicLibrary.process();
final posixFree = stdlib.lookup<NativeFunction<Void Function(Pointer)>>('free');

class Utf8Resource implements Finalizable {
  static final NativeFinalizer _finalizer = NativeFinalizer(posixFree);

  /// [_cString] must never escape [Utf8Resource], otherwise the
  /// [_finalizer] will run prematurely.
  final Pointer<Utf8> _cstr;
  Utf8Resource(this._cstr) {
    _finalizer.attach(this, _cstr.cast(), detach: this);
  }
  void free() {
    _finalizer.detach(this);
    calloc.free(_cstr);
  }

  /// Ensure this [Utf8Resource] stays in scope longer than the inner resource.
  Pointer<Utf8> unsafe() => _cstr;
}
